package com.ytktt.study.week8.task6.hmily.tcc.account.service;

import com.ytktt.study.week8.task6.hmily.tcc.account.api.AccountService;
import com.ytktt.study.week8.task6.hmily.tcc.account.dto.AccountDTO;
import com.ytktt.study.week8.task6.hmily.tcc.account.dto.AccountNestedDTO;
import com.ytktt.study.week8.task6.hmily.tcc.account.entity.AccountEntity;
import com.ytktt.study.week8.task6.hmily.tcc.account.mapper.AccountMapper;
import com.ytktt.study.week8.task6.hmily.tcc.stock.api.ItemStockService;
import com.ytktt.study.week8.task6.hmily.tcc.stock.dto.ItemStockDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * TODO
 *
 * @author ytk
 */
@Slf4j
@Service("accountService")
@RequiredArgsConstructor
public class AccountServiceImpl implements AccountService {

    private static final AtomicInteger CONFIRM_COUNT = new AtomicInteger(0);
    private final AccountMapper accountMapper;
    private final ItemStockService itemStockService;

    @Override
    @HmilyTCC(confirmMethod = "confirm", cancelMethod = "cancel")
    public boolean payment(AccountDTO accountDTO) {
        int count =  accountMapper.update(this.convertDtoToEntity(accountDTO));
        if (count > 0) {
            return true;
        } else {
            throw new IllegalArgumentException("账户扣减异常");
        }
    }

    @Override
    @HmilyTCC(confirmMethod = "confirm", cancelMethod = "cancel")
    public boolean mockTryPaymentException(AccountDTO accountDTO) {
        throw new IllegalArgumentException("账户扣减异常");
    }

    @Override
    @HmilyTCC(confirmMethod = "confirm", cancelMethod = "cancel")
    public boolean mockTryPaymentTimeout(AccountDTO accountDTO) {
        try {
            //模拟延迟 当前线程暂停10秒
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final int decrease = this.accountMapper.update(this.convertDtoToEntity(accountDTO));
        if (decrease != 1) {
            throw new IllegalArgumentException("账户扣减异常");
        }
        return true;
    }

    @Override
    public boolean testPayment(AccountDTO accountDTO) {
        this.accountMapper.testUpdate(this.convertDtoToEntity(accountDTO));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @HmilyTCC(confirmMethod = "confirmNested", cancelMethod = "cancelNested")
    public boolean paymentWithNested(AccountNestedDTO accountNestedDTO) {
        this.accountMapper.update(this.convertNestedDtoToEntity(accountNestedDTO));
        ItemStockDTO itemStockDTO = new ItemStockDTO();
        itemStockDTO.setItemId(accountNestedDTO.getItemId());
        itemStockDTO.setAmount(accountNestedDTO.getItemAmount());
        this.itemStockService.decrease(itemStockDTO);
        return true;
    }

    @Override
    public boolean paymentWithNestedException(AccountNestedDTO accountNestedDTO) {
        this.accountMapper.update(this.convertNestedDtoToEntity(accountNestedDTO));
        ItemStockDTO itemStockDTO = new ItemStockDTO();
        itemStockDTO.setItemId(accountNestedDTO.getItemId());
        itemStockDTO.setAmount(accountNestedDTO.getItemAmount());
        this.itemStockService.decrease(itemStockDTO);
        this.itemStockService.mockWithTryException(itemStockDTO);
        return true;
    }

    @Override
    public AccountEntity getByUserId(Integer userId) {
        return this.accountMapper.selectByUserId(userId);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean confirmNested(AccountNestedDTO accountNestedDTO) {
        log.debug("============dubbo tcc 执行确认付款接口===============");
        this.accountMapper.updateConfirm(this.convertNestedDtoToEntity(accountNestedDTO));
        return true;
    }

    /**
     * Cancel nested boolean.
     *
     * @param accountNestedDTO the account nested dto
     * @return the boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean cancelNested(AccountNestedDTO accountNestedDTO) {
        log.debug("============ dubbo tcc 执行取消付款接口===============");
        this.accountMapper.updateCancel(this.convertNestedDtoToEntity(accountNestedDTO));
        return true;
    }

    /**
     * Confirm boolean.
     *
     * @param accountDTO the account dto
     * @return the boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean confirm(AccountDTO accountDTO) {
        log.info("============dubbo tcc 执行确认付款接口===============");
        accountMapper.updateConfirm(this.convertDtoToEntity(accountDTO));
        final int i = CONFIRM_COUNT.incrementAndGet();
        log.info("调用了account confirm " + i + " 次");
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean cancel(AccountDTO accountDTO) {
        log.info("============ dubbo tcc 执行取消付款接口===============");
        this.accountMapper.updateCancel(this.convertDtoToEntity(accountDTO));
        return true;
    }

    private AccountEntity convertDtoToEntity(AccountDTO accountDTO) {
        AccountEntity entity = new AccountEntity();
        entity.setUserId(accountDTO.getUserId());
        entity.setFreezeAmount(accountDTO.getPayAmount());
        return entity;
    }

    private AccountEntity convertNestedDtoToEntity(AccountNestedDTO accountNestedDTO) {
        AccountEntity entity = new AccountEntity();
        entity.setUserId(accountNestedDTO.getUserId());
        entity.setFreezeAmount(accountNestedDTO.getPayAmount());
        return entity;
    }
}
